package ${d.pkg};

<#list d.imports as imps>
import ${imps};
</#list>
import org.apache.ibatis.annotations.Param;

/**
 *	Dao (${d.e.tableName})
 *  ${d.e.tableDesc!""}
 *
 *	@author ${d.e.author!""} (${d.e.authorEnglish!""})
 *	@date ${d.e.createTime}
 */
@${d.annotationName}
public interface ${d.className} {
    /**
     *  查询全部数据（慎用！！！）
     */
    @${d.annotationShardClassName}<#if d.shardAutoCreateTable>(autoCreateTable = true)</#if>
    List<${d.e.className}> findAllWithShardSuffix(@Param("fields") ${d.fe.className} fields, @Param("shardSuffix") String shardSuffix);


    /**
     *  条件查询
     *  <p> 如果queries中路由到多表，默认的aggregator会把结果按表名的ascii序拼接
     */
    @${d.annotationShardClassName}<#if d.shardAutoCreateTable>(autoCreateTable = true)</#if>
    List<${d.e.className}> findByQuery(
                @Param("fields") ${d.fe.className} fields,
                @${d.annotationShardRouterClassName}(router=${d.routerQueryClassName}.class) @Param("query") ${d.q.className} query);
    /**
     *  条件查询
     *  <p> 已经完整指定表名，无需router
     */
    @${d.annotationShardClassName}<#if d.shardAutoCreateTable>(autoCreateTable = true)</#if>
    List<${d.e.className}> findByQueryWithOrderBy(
                @Param("fields") ${d.fe.className} fields,
                @${d.annotationShardRouterClassName}(router=${d.routerQueryClassName}.class) @Param("query") ${d.q.className} query,
                @Param("orderBy") ${d.ob.className} orderBy);


    /**
     *  查询总数
     */
    @${d.annotationShardClassName}<#if d.shardAutoCreateTable>(autoCreateTable = true)</#if>
    int count(@Param("shardSuffix") String shardSuffix);
    /**
     *  条件查询数量
     */
    @${d.annotationShardClassName}<#if d.shardAutoCreateTable>(autoCreateTable = true)</#if>
    int countByQuery(@${d.annotationShardRouterClassName}(router=${d.routerQueryClassName}.class) @Param("query") ${d.q.className} query);
    /**
     *  查询在执行limit条件下的数量和极值
     *  <p> 给分页用的，其他场景用不到
     */
    @${d.annotationShardClassName}<#if d.shardAutoCreateTable>(autoCreateTable = true)</#if>
    ${d.pc.className} countByQueryWithOrderBy(
                @Param("page") Pager<${d.e.className}> pager,
                @${d.annotationShardRouterClassName}(router=${d.routerQueryClassName}.class) @Param("query") ${d.q.className} query,
                @Param("orderBy") ${d.ob.className} orderBy);
    /**
     *  查询极值左边的数量和等于极值的数量
     *  <p> 给分页用的，其他场景用不到
     *  <p> 极值保存在orderBy.getCurrentItem().getVal()中
     *  @return 0:极值左边的数量 1:等于极值的数量
     */
    @${d.annotationShardClassName}<#if d.shardAutoCreateTable>(autoCreateTable = true)</#if>
    List<Integer> countByQueryWithExtreme(
                @Param("page") Pager<${d.e.className}> pager,
                @${d.annotationShardRouterClassName}(router=${d.routerQueryClassName}.class) @Param("query") ${d.q.className} query,
                @Param("orderBy") ${d.ob.className} orderBy);


    /**
     *  分页查询
     *  <p> 分页字段一定得是唯一键
     *  <p> 上一轮排序值存储在 orderBy.items.get(0).val 中
     *  <p> 通过orderBy对象进行传递，所以多轮查询之间需要共用一个orderBy对象
     *  <p> 或者orderBy.setFirstItemVal()传递
     */
    @${d.annotationShardClassName}<#if d.shardAutoCreateTable>(autoCreateTable = true)</#if>
    @Pagement(count="countByQuery")
    Pager<${d.e.className}> findByAfterPage(
                @Param("fields") ${d.fe.className} fields,
                @Param("page") ${d.afterPagerClassName}<${d.e.className}> pager,
                @${d.annotationShardRouterClassName}(router=${d.routerQueryClassName}.class) @Param("query") ${d.q.className} query,
                @Param("orderBy") ${d.ob.className} orderBy);
    /**
     *  分页查询
     *  <p> 会按照表名的ascii序，优先取前几张表凑够本页数量
     *  <p> 不推荐使用：聚合需要消耗大量本地内存
     *  <p> 且mysql的排序是不稳定排序，当排序字段中不含唯一索引时，不能保证排序结果。
     */
    @${d.annotationShardClassName}<#if d.shardAutoCreateTable>(autoCreateTable = true)</#if>
    @Pagement(count="countByQuery")
    @Deprecated
    Pager<${d.e.className}> findByPage(
                @Param("fields") ${d.fe.className} fields,
                @Param("page") Pager<${d.e.className}> pager,
                @${d.annotationShardRouterClassName}(router=${d.routerQueryClassName}.class) @Param("query") ${d.q.className} query);
    /**
     *  分页查询
     *  <p> 如果queries中出现了多表，默认会按照orderBy中定义的顺序取pageSize条记录
     *  <p> 不推荐使用：聚合需要消耗大量本地内存
     *  <p> 且mysql的排序是不稳定排序，当排序字段中不含唯一索引时，不能保证排序结果。
     */
    @${d.annotationShardClassName}<#if d.shardAutoCreateTable>(autoCreateTable = true)</#if>
    @Pagement(count="countByQuery")
    @Deprecated
    Pager<${d.e.className}> findByPageWithOrderBy(
                @Param("fields") ${d.fe.className} fields,
                @Param("page") Pager<${d.e.className}> pager,
                @${d.annotationShardRouterClassName}(router=${d.routerQueryClassName}.class) @Param("query") ${d.q.className} query,
                @Param("orderBy") ${d.ob.className} orderBy);


    /**
     *  插入
     *  <p> 如果存在唯一自增主键字段，则insert完成后该字段保存该条记录自增的值（不过shard模式下推荐分布式id，shard中自带SnowIdGenerator）
     */
    @${d.annotationShardClassName}<#if d.shardAutoCreateTable>(autoCreateTable = true)</#if>
    @${d.annotationShardTransactionClassName}
    void insert(@${d.annotationShardRouterClassName}(router=${d.routerDOClassName}.class) @Param("entity") ${d.e.className} entity);
    /**
     *  批量插入
     *  <p> 如果存在唯一自增主键字段，则insert完成后该字段保存该条记录自增的值（不过shard模式下推荐分布式id，shard中自带SnowIdGenerator）
     *  <p> 会调用 org.ala.tiktools.sharddb.mybatis.handler.IShardTableHandler 生成@Param("shardSuffix")参数
     *  <p> 如果 org.ala.tiktools.sharddb.mybatis.handler.IShardTableHandler 最终生成了多份 shardSuffix，分表之间组成本地分布式事务（单个分表走原生事务）
     */
    @${d.annotationShardClassName}<#if d.shardAutoCreateTable>(autoCreateTable = true)</#if>
    @${d.annotationShardTransactionClassName}
    void multipleInsert(@${d.annotationShardRouterClassName}(router=${d.routerDOListClassName}.class) @Param("entities") List<${d.e.className}> entities);


    /**
     *  修改
     *  <p> 注：如果修改了分偏键，这里不会进行迁移
     */
    @${d.annotationShardClassName}<#if d.shardAutoCreateTable>(autoCreateTable = true)</#if>
    @${d.annotationShardTransactionClassName}
    int update(@Param("entity") ${d.e.className} entity,
                @${d.annotationShardRouterClassName}(router=${d.routerQueryClassName}.class) @Param("query") ${d.q.className} query);
    /**
     *  批量修改
     *  <p> 每个MultipleUpdate对应一个update语句
     *  <p> 在某些mysql + mybatis的版本中，可能只返回第一条update的影响行数
     */
    @${d.annotationShardClassName}<#if d.shardAutoCreateTable>(autoCreateTable = true)</#if>
    @${d.annotationShardTransactionClassName}
    int multipleUpdate(@${d.annotationShardRouterClassName}(router=${d.routerMUClassName}.class) @Param("updates") List<MultipleUpdate> multipleUpdates);


    /**
     *  删除
     */
    @${d.annotationShardClassName}<#if d.shardAutoCreateTable>(autoCreateTable = true)</#if>
    @${d.annotationShardTransactionClassName}
    int delete(@${d.annotationShardRouterClassName}(router=${d.routerQueryClassName}.class) @Param("query") ${d.q.className} query);


    /**
     *  建表语句
     *  <p> 只能建当前线程环境的分库下的分表。如果要自行调用，需要ThreadLocalLookupKey指定分库，不指定则默认default分库
     *  <p> 分库信息在 ShardDBConfiguration.DBS 查看
     */
    void createTable(@Param("shardSuffix") String shardSuffix);
    /**
     *  所有分表
     *  <p> 只能查看当前线程环境指定的分库下，的所有分表
     *  <p> 要看所有分库可以从 ShardDBConfiguration.DBS 里拿所有分库配置，自行遍历
     */
    List<String> allTables();


    /**
     *  批量修改参数
     */
    public static class MultipleUpdate extends ${d.mutileUpdateName}<${d.e.className}, ${d.q.className}> {
        public MultipleUpdate(${d.e.className} entity, ${d.q.className} query) {
            super(entity, query);
        }
        public static MultipleUpdate build(${d.e.className} entity, ${d.q.className} query) {
            return new MultipleUpdate(entity, query);
        }
        /**
         *  copy（注：这是浅拷贝）
         */
        public MultipleUpdate copy() {
            return new MultipleUpdate(entity.copy(), query.copy());
        }
    }
}